//
// PicoMax
// Copyright 2012 Thomas W. Holtquist
// www.skewworks.com
//
// GPL 3.0 Licensed
//

using System;
using System.IO;

using Microsoft.SPOT;

namespace Skewworks.PicoMax.Graphics565
{

    /// <summary>
    /// Minimal font support
    /// </summary>
    public class PicoFont
    {

        #region Variables

        private bool _fixedWidth;
        private bool _antiAlias;

        protected internal int[] _lookups;
        protected internal byte[] _sizes;
        protected internal byte[] _fontData;

        private int _fontHeight;

        #endregion

        #region Constructors

        /// <summary>
        /// Creates a new PicoFont from file
        /// </summary>
        /// <param name="Filename">PicoFont filename</param>
        public PicoFont(string Filename)
        {
            LoadPicoFont(File.ReadAllBytes(Filename));
        }

        /// <summary>
        /// Creates a new PicoFont from raw data
        /// </summary>
        /// <param name="Data">PicoFont data</param>
        public PicoFont(byte[] Data)
        {
            LoadPicoFont(Data);
        }

        #endregion

        #region Properties

        /// <summary>
        /// True if font has anti-aliasing
        /// </summary>
        public bool AntiAliased
        {
            get { return _antiAlias; }
        }

        /// <summary>
        /// True if font is fixed width
        /// </summary>
        public bool FixedWidth
        {
            get { return _fixedWidth; }
        }

        /// <summary>
        /// Height of font
        /// </summary>
        public int FontHeight
        {
            get { return _fontHeight; }
        }

        #endregion

        #region Public Methods

        public void ComputeExtent(string Text, out int Width, out int Height)
        {
            Size sz = MeasureString(Text);
            Width = sz.Width;
            Height = sz.Height;
        }

        public Size ComputeExtentEX(string Text)
        {
            int w = 0;
            Size sz = new Size();

            string[] lines = Text.Split('\n');

            for (int i = 0; i < lines.Length; i++)
            {
                w = MeasureString(lines[i]).Width;
                if (w > sz.Width) 
                    sz.Width = w;
            }

            sz.Height = _fontHeight * lines.Length;

            return sz;
        }

        public void ComputeExtentInRect(string Text, out int Width, out int Height, int AvailableWidth)
        {
            int w = 0;
            int addLines = 0;
            Size sz = new Size();

            string[] lines = Text.Split('\n');

            for (int i = 0; i < lines.Length; i++)
            {
                w = MeasureString(lines[i]).Width;
                if (w > AvailableWidth)
                {
                    addLines += w / AvailableWidth;
                    w = AvailableWidth;
                }
                if (w > sz.Width)
                    sz.Width = w;
            }

            Width = sz.Width;
            Height = _fontHeight * (lines.Length + addLines);
        }

        /// <summary>
        /// Returns Height & Width of specified character
        /// </summary>
        /// <param name="Character">Character to measure</param>
        /// <returns></returns>
        public Size MeasureCharacter(char Character)
        {
            if (Character < 33 || Character > 126)
                return new Size(((_sizes[23] * ((_antiAlias) ? 2 : 8)) / _fontHeight) - 1, _fontHeight);
            return new Size(((_sizes[Character - 33] * ((_antiAlias) ? 2 : 8)) / _fontHeight), _fontHeight);
        }

        /// <summary>
        /// Returns Height & Width of specified string
        /// </summary>
        /// <param name="Text">Text to measure</param>
        /// <returns></returns>
        public Size MeasureString(string Text)
        {
            int w = 0;

            for (int i = 0; i < Text.Length; i++)
            {
                if (Text[i] < 33 || Text[i] > 126)
                    w += ((_sizes[23] * ((_antiAlias) ? 2 : 8)) / _fontHeight);
                else
                    w += ((_sizes[Text[i] - 33] * ((_antiAlias) ? 2 : 8)) / _fontHeight) + 1;
            }
            return new Size(w - 1, _fontHeight);
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Loads PicoFont from byte array
        /// </summary>
        /// <param name="Data"></param>
        private void LoadPicoFont(byte[] Data)
        {
            int i;
            int len;
            int dStart = 5;
            int fdStart = 0;
            int totalOffset = 0;

            if (Data[0] != 112 || Data[1] != 70 || Data[2] != 110 || Data[3] != 116)
                throw new InvalidCastException("Invalid file format");

            if (Data[4] == 1 || Data[4] == 3)
                _fixedWidth = true;

            if (Data[4] == 2 || Data[4] == 3)
                _antiAlias = true;

            // Font Height
            _fontHeight = Data[dStart++];

            if (!_fixedWidth)
            {
                // Create Lookups (character count - 1)
                _sizes = new byte[94];
                _lookups = new int[94];

                // Create Font Data
                _fontData = new byte[Data.Length - 5 - 92];

                for (i = 0; i < 94; i++)
                {
                    // Get Font Length
                    len = Data[dStart++];
                    _sizes[i] = (byte)len;
                    _lookups[i] = totalOffset;
                    totalOffset += len;

                    // Copy Data
                    Array.Copy(Data, dStart, _fontData, fdStart, len);
                    dStart += len;
                    fdStart += len;
                }
            }
        }

        #endregion

    }

}
